package com.founder.devwork.service.impl;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.founder.devwork.dto.req.CommitLogQueryDTO;
import com.founder.devwork.dto.res.AmountDistributionDTO;
import com.founder.devwork.dto.res.AuthorInfoDTO;
import com.founder.devwork.dto.res.CommitLogDTO;
import com.founder.devwork.dto.res.DistributionStatsDTO;
import com.founder.devwork.dto.res.HourlyStatsDTO;
import com.founder.devwork.dto.res.MonthlyEngineerStatsDTO;
import com.founder.devwork.dto.res.MonthlyRepoStatsDTO;
import com.founder.devwork.dto.res.TopCommitterDTO;
import com.founder.devwork.dto.res.TopRepositoryDTO;
import com.founder.devwork.dto.res.WeeklyStatsDTO;
import com.founder.devwork.entity.CommitLog;
import com.founder.devwork.persistence.mapper.CommitLogMapper;
import com.founder.devwork.service.CommitLogService;
import java.time.temporal.ChronoUnit;
import java.util.Collection;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * CommitLogServiceImpl 用于实现 CommitLogService 接口。
 * 提供查询提交统计信息的方法。
 */
@Service
public class CommitLogServiceImpl extends ServiceImpl<CommitLogMapper, CommitLog> implements CommitLogService {

    @Autowired
    private CommitLogMapper commitLogMapper;

    /**
     * 保存提交日志，重写是为了Hibernate Validation
     *
     * @param entity 提交日志实体
     * @return 是否保存成功
     */
    @Override
    public boolean save(CommitLog entity) {
        return super.save(entity);
    }

    /**
     * 批量保存提交日志，重写是为了Hibernate Validation
     *
     * @param entityList 提交日志实体列表
     * @return 是否批量保存成功
     */
    @Override
    public boolean saveBatch(Collection<CommitLog> entityList) {
        return super.saveBatch(entityList);
    }

    /**
     * @inheritDoc
     */
    @Override
    public List<TopCommitterDTO> getTopByCommitCount(int limit, String sortBy, String sortDirection) {
        if (sortBy == null || sortBy.isEmpty()) {
            sortBy = "total_changes";
        }
        if (sortDirection == null || sortDirection.isEmpty()) {
            sortDirection = "DESC";
        }
        List<TopCommitterDTO> list;
        if (limit > 0) {
            list = this.commitLogMapper.selectTopByCommitCount(limit, sortBy, sortDirection);
        } else {
            list = this.commitLogMapper.selectAllByCommitCount(sortBy, sortDirection);
        }
        for (TopCommitterDTO dto : list) {
            if (dto.getMinDate() != null && dto.getMaxDate() != null) {
                long months = ChronoUnit.MONTHS.between(dto.getMinDate(), dto.getMaxDate()) + 1;
                if (months == 0) months = 1;
                dto.setAverageMonthlyCommits(dto.getCommitCount() / (double) months);
                dto.setAverageMonthlyChanges(dto.getTotalChanges() / (double) months);
            } else {
                dto.setAverageMonthlyCommits(0);
                dto.setAverageMonthlyChanges(0);
            }
            // 清空临时字段
            dto.setMinDate(null);
            dto.setMaxDate(null);
        }
        return list;
    }

    /**
     * @inheritDoc
     */
    @Override
    public List<TopCommitterDTO> getTopLastMonthByCommitCount(int limit, String sortBy, String sortDirection) {
        if (sortBy == null || sortBy.isEmpty()) {
            sortBy = "total_changes";
        }
        if (sortDirection == null || sortDirection.isEmpty()) {
            sortDirection = "DESC";
        }
        if (limit > 0) {
            return this.commitLogMapper.selectTopLastMonthByCommitCount(limit, sortBy, sortDirection);
        } else {
            return this.commitLogMapper.selectAllLastMonthByCommitCount(sortBy, sortDirection);
        }
    }

    /**
     * @inheritDoc
     */
    @Override
    public List<TopRepositoryDTO> getTopLastMonthRepositoriesByChanges(int limit) {
        return this.commitLogMapper.selectTopLastMonthRepositoriesByChanges(limit);
    }

    /**
     * @inheritDoc
     */
    @Override
    public List<MonthlyRepoStatsDTO> getMonthlyStatsForRepo(String gitInstance, String repositoryId) {
        return this.commitLogMapper.selectMonthlyStatsForRepo(gitInstance, repositoryId);
    }

    /**
     * @inheritDoc
     */
    @Override
    public List<MonthlyEngineerStatsDTO> getMonthlyStatsForEngineer(String engineerId) {
        return this.commitLogMapper.selectMonthlyStatsForEngineer(engineerId);
    }

    /**
     * @inheritDoc
     */
    @Override
    public List<HourlyStatsDTO> getHourlyStats(String engineerId) {
        return this.commitLogMapper.selectHourlyStats(engineerId);
    }

    /**
     * @inheritDoc
     */
    @Override
    public List<WeeklyStatsDTO> getWeeklyStats(String engineerId) {
        return this.commitLogMapper.selectWeeklyStats(engineerId);
    }

    /**
     * @inheritDoc
     */
    @Override
    public DistributionStatsDTO getCommitAmountDistribution() {
        List<AmountDistributionDTO> dist = commitLogMapper.selectCommitAmountDistribution();
        DistributionStatsDTO dto = new DistributionStatsDTO();
        dto.setDistributions(dist);

        long count = commitLogMapper.selectCommitCount();
        if (count == 0) {
            dto.setAverage(0);
            dto.setMedian(0);
        } else {
            double average = commitLogMapper.selectCommitAverage();
            int offset = (int) ((count - 1) / 2);
            List<Integer> values = commitLogMapper.selectCommitMedianValues(offset);
            double median = values.stream().mapToDouble(Integer::doubleValue).average().orElse(0);
            dto.setAverage(average);
            dto.setMedian(median);
        }
        return dto;
    }

    /**
     * @inheritDoc
     */
    @Override
    public DistributionStatsDTO getDailyEngineerAmountDistribution() {
        List<AmountDistributionDTO> dist = commitLogMapper.selectDailyEngineerAmountDistribution();
        DistributionStatsDTO dto = new DistributionStatsDTO();
        dto.setDistributions(dist);

        long count = commitLogMapper.selectDailyEngineerCount();
        if (count == 0) {
            dto.setAverage(0);
            dto.setMedian(0);
        } else {
            double average = commitLogMapper.selectDailyEngineerAverage();
            int offset = (int) ((count - 1) / 2);
            List<Integer> values = commitLogMapper.selectDailyEngineerMedianValues(offset);
            double median = values.stream().mapToDouble(Integer::doubleValue).average().orElse(0);
            dto.setAverage(average);
            dto.setMedian(median);
        }
        return dto;
    }

    /**
     * @inheritDoc
     */
    @Override
    public Page<CommitLogDTO> pageCommitLogsWithQuery(int pageNum, int pageSize, CommitLogQueryDTO query) {
        long total = commitLogMapper.countCommitLogsWithQuery(query);
        List<CommitLogDTO> records = commitLogMapper.selectCommitLogsWithQuery(query, (pageNum - 1) * pageSize, pageSize);
        Page<CommitLogDTO> page = new Page<>(pageNum, pageSize, total);
        page.setRecords(records);
        return page;
    }

    @Override
    public List<AuthorInfoDTO> getDistinctAuthors() {
        return commitLogMapper.selectDistinctAuthors();
    }
}
